package com.example.service.impl;

import cn.hutool.core.io.FileUtil;
import com.example.domain.dto.ExportDTO;
import com.example.mapper.CustInfoMapper;
import com.example.service.FileUploadService;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.*;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
@Slf4j
public class FileUploadServiceImpl implements FileUploadService {
    @Autowired
    private CustInfoMapper custInfoMapper;

    @Override
    public void export(HttpServletResponse response) {
        String s =  System.getProperty("user.dir") + "/download/custInfo.zip";
        File file = new File(s);
        response.setContentType("application/zip");
        response.setHeader("Content-Disposition", "attachment;filename=\"custInfo.zip\"");
        try(
            ServletOutputStream outputStream = response.getOutputStream();
        ){
            outputStream.write(FileUtil.readBytes(file));
        }catch (Exception e){
            e.printStackTrace();
        }
    }

//    @Override
//    public Double build(ExportDTO exportDTO, HttpServletResponse response) {
//
//        long startTime = System.currentTimeMillis();
//        List<String> custInfos = custInfoMapper.export(exportDTO);
//        long endTime = System.currentTimeMillis();
//        Double time = 1.0 * (endTime - startTime)/1000;
//        log.info("批量查询耗时：{}s", 1.0 * (endTime - startTime)/1000);
//        // 定义ZIP文件的保存路径
//        String s =  System.getProperty("user.dir") + "/download/custInfo.zip";
//        // 创建文件和ZIP输出流
//        try (FileOutputStream fos = new FileOutputStream(s);
//             ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(fos))) {
//
//            // 创建TXT文件的ZIP条目
//            ZipEntry zipEntry = new ZipEntry("custInfo.txt");
//            zos.putNextEntry(zipEntry);
//
//            // 将数据写入TXT文件中
//            for (String info : custInfos) {
//                zos.write((info + System.lineSeparator()).getBytes());
//            }
//
//            // 完成当前条目
//            zos.closeEntry();
//
//            // 完成ZIP文件的写入
//            zos.finish();
//
//        } catch (IOException e) {
//            e.printStackTrace();
//            // 处理异常
//        }
//        return time;
//    }
    @Override
    public Double build(ExportDTO exportDTO, HttpServletResponse response) {
        long startTime = System.currentTimeMillis();

//        int totalRecords = 5000000;
        // 总记录数
        long totalRecords = custInfoMapper.selectCount(null);
        long cnt = Runtime.getRuntime().availableProcessors();
        long batchSize = (int) Math.ceil((double) totalRecords / cnt);

        log.info("核心线程数{}",Runtime.getRuntime().availableProcessors());
        // 自己配置线程池
        ExecutorService executor = new ThreadPoolExecutor(
                Runtime.getRuntime().availableProcessors(),  // corePoolSize
                Runtime.getRuntime().availableProcessors(),  // maximumPoolSize
//                8, 16,
                60L,  // keepAliveTime
                TimeUnit.SECONDS,  // unit
                new LinkedBlockingQueue<>(1024),  // workQueue
                Executors.defaultThreadFactory(),  // threadFactory（默认线程工厂）
                new ThreadPoolExecutor.AbortPolicy()  // 拒绝策略, 这里使用AbortPolicy，直接抛出异常
        );


        // 使用线程池并行查询
//        ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
        List<Future<List<String>>> futures = new ArrayList<>();

        for (int i = 0; i < cnt; i++) {
            long startId = i * batchSize; // 计算偏移量
            long endId = Math.min((i + 1) * batchSize, totalRecords);
            futures.add(executor.submit(() -> { // 提交任务
                long threadStartTime = System.currentTimeMillis();
                try {
//                    return custInfoMapper.export2(exportDTO , startId, endId); //分段查询
                    List<String> result = custInfoMapper.export2(exportDTO, startId, endId); // 分段查询
                    long threadEndTime = System.currentTimeMillis();
                    double threadTime = 1.0 * (threadEndTime - threadStartTime) / 1000;
                    log.info("线程{}查询耗时：{}s，offset={}, batchSize={}",Thread.currentThread().getName() , threadTime, startId, endId);
                    return result;
                } catch (Exception e) {
                    log.error("查询失败，offset={}, batchSize={}", startId, endId, e);
                    return Collections.emptyList(); // 返回空集合以确保汇总不会报错
                }
            }));
        }


        List<String> custInfos = new ArrayList<>();
        try {
            for (Future<List<String>> future : futures) {
                try {
                    custInfos.addAll(future.get(5, TimeUnit.MINUTES)); // 等待每个任务的结果
                } catch (TimeoutException e){
                    log.error("查询超时",  e);
                } catch (Exception e) {
                    futures.forEach(f -> f.cancel(true)); // 其他任务失败时取消所有任务
                    throw new RuntimeException("批量查询失败", e);
                }
            }
        } catch (Exception e) {
            log.error("批量查询失败", e);
        } finally {
            executor.shutdown();
        }

        long endTime = System.currentTimeMillis();
        Double time = 1.0 * (endTime - startTime) / 1000;
        log.info("批量查询耗时：{}s", time);

        // 定义 ZIP 文件的保存路径
        String zipFilePath = System.getProperty("user.dir") + "/download/custInfo.zip";

        // 创建文件和 ZIP 输出流
        try (FileOutputStream fos = new FileOutputStream(zipFilePath);
             ZipOutputStream zos = new ZipOutputStream(new BufferedOutputStream(fos))) {
            // 创建 TXT 文件的 ZIP 条目
            ZipEntry zipEntry = new ZipEntry("custInfo.txt");
            zos.putNextEntry(zipEntry);
            // 将数据写入 TXT 文件中
            for (String info : custInfos) {
                zos.write((info + System.lineSeparator()).getBytes());
            }
            // 完成当前条目
            zos.closeEntry();
            zos.finish();
        } catch (IOException e) {
            log.error("文件写入失败", e);
        }
        return time;
    }
}
